#include "cube.h"
#include "light.h"
#include <gvector3d.h>
#include <gmatrix3d.h>
#include <ggltools.h>
#include <GL/glut.h>
#include <stdio.h>

//archball


int gMouseX = -1;
int gMouseY = -1;

// ÊÇ·ñ½øÐÐÊó±ê×·×ÙÇò 
bool gIsStartTrackBall = false;

// Ðý×ª¾ØÕó 
GMatrix3d gRotMatrix;


//define wheel
const GLuint GLUT_WHEEL_UP = 3;
const GLuint GLUT_WHEEL_DOWN = 4;
GLfloat zoom = -150.0f;

//define light
GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };
GLfloat lightPos[] = {20.0f, 20.0f, 50.0f};
Light light0(ambientLight, diffuseLight, lightPos);

//define cube
Cube myCube;

GVector3d gMousePtToSphereVec(int x, int y, int w, int h)
{
    GVector3d vec;
    vec.setX((2.0*x-w)/w);
    vec.setY((h-2.0*y)/h);
    double r=vec.x()*vec.x()+vec.y()*vec.y();
    if(r>1)r=1;
    vec.setZ(sqrt(1-r));
    vec.normalize();
    return vec;
}


void init()
{

    glEnable(GL_DEPTH_TEST);
    glFrontFace(GL_CCW);
    glEnable(GL_CULL_FACE);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    glEnable(GL_LIGHTING);  //enable light

    glShadeModel(GL_FLAT);  //chage shade model
    // Enable color tracking
    glEnable(GL_COLOR_MATERIAL);
    // Set material properties to follow glColor values
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    glEnable(GL_NORMALIZE); //enable normalize

    light0.enable();
    //texutre features are not added
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);


}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(0.0f, 0.0f, zoom, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
    glPushMatrix();
    glMultMatrixd(gRotMatrix);      //perform archball

    myCube.glDraw();                //draw scence
    glPopMatrix();

    glFlush();
    glutSwapBuffers();

}

        

// Êó±êÊÂ¼þº¯Êý 
void mouseEvent(int button, int state, int x, int y)
{
    if(button == GLUT_LEFT_BUTTON)
    {
        if(state == GLUT_DOWN)
        {
            gMouseX = x;
            gMouseY = y;
            gIsStartTrackBall = true;
        }
        else if(state == GLUT_UP)
        {    
            gIsStartTrackBall = false;
        }            
        //glutPostRedisplay();
    }
    //process wheel to zoom in and zoom out
    //if ( zoom <= -100 && zoom >= -1000)
    {
    if (state == GLUT_UP && button == GLUT_WHEEL_UP)
    {
        zoom += 3.0f;
    //    glutPostRedisplay();
    }
    if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
    {
        zoom -= 3.0f;
        //glutPostRedisplay();
    }
    }
}
void changeSize(int w, int h)
{
    GLfloat aspectRatio;


    //prevent a divide by zero
    if(h==0)
        h = 1;
    //Set Viewport
    glViewport(0, 0, w, h);

    //reset coordinate system
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //Establish clipping voluem(left, right, bottom, top, near, far)
    aspectRatio = (GLfloat)w / (GLfloat)h;
    /*
    if(w<=h)
        glOrtho(-100.0, 100.0, -100 / aspectRatio, 100.0 * aspectRatio, 100.0, -100.0);
    else
        glOrtho(-100.0 * aspectRatio, 100.0 * aspectRatio, -100.0, 100.0, 100.0, -100.0);
        */
    gluPerspective(45.0f, aspectRatio, 1.0f, 500.0f);    //using perspective
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void mouseMoveEvent(int x, int y)
{
    if(gIsStartTrackBall)
    {
        if(x!=gMouseX||y!=gMouseY)
        {
            int w=glutGet(GLUT_WINDOW_WIDTH);
            int h=glutGet(GLUT_WINDOW_HEIGHT);
            GVector3d lastVec,currentVec,axis;
            double rotAngle;
            lastVec=gMousePtToSphereVec(gMouseX,h-gMouseY,w,h);
            currentVec=gMousePtToSphereVec(x,h-y,w,h);
            axis=lastVec.crossMult(currentVec);
            axis.normalize();
            rotAngle=acos(lastVec.dotMult(currentVec));
            rotAngle*=RADIAN_TO_ANGLE;
            gMouseX=x;gMouseY=y;

         //¿¼ÊÔÌâ
            GMatrix3d m=GMatrix3d::createRotate(rotAngle,axis);
            gRotMatrix *=m;

            //glutPostRedisplay();
        }

    }
}

void SpecialKeys(int key, int x, int y)
{
    if(key == GLUT_KEY_UP)
    {
        myCube.rotate('u');
    }
    if(key == GLUT_KEY_DOWN)
    {
        myCube.rotate('d');
    }
    if(key == GLUT_KEY_LEFT)
    {
        myCube.rotate('l');
    }
    if(key == GLUT_KEY_RIGHT)
    {
        myCube.rotate('r');
    }
    if(key == GLUT_KEY_PAGE_UP)
    {
        myCube.rotate('f');
    }
    if(key == GLUT_KEY_PAGE_DOWN)
    {
        myCube.rotate('b');
    }

}

void timerFunction(int value)       
    //force it to refresh, no need of postRedisplay function any more
{
    //change values here
    
    glutPostRedisplay();
    glutTimerFunc(10,timerFunction,1);
}

int main( int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Cube");
    glutDisplayFunc(display);
    glutReshapeFunc(changeSize);
    glutTimerFunc(10, timerFunction, 1);
    
    glutMouseFunc(mouseEvent);
    glutMotionFunc(mouseMoveEvent);
    glutSpecialFunc(SpecialKeys);
    init();
    

    glutMainLoop();

    return 0;
}


